package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"reflect"
	"regexp"
	"strconv"
	"strings"
)

func p(i interface{}) {
	fmt.Println(i)
}
func checkErr(errMasg error) {
	if errMasg != nil {
		fmt.Println(errMasg)
		//panic(errMasg)
	}
}

var dbsmap = map[string]string{
	"db0": "slave:slave@tcp(weidian.54json.com:3306)/blog?charset=utf8",
	"db1": "root:aide521521@tcp(localhost:3306)/testshop?charset=utf8",
}
var dbs = make(map[string]*sql.DB)

func M(dbname string) *DB {
	Db := new(DB)
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()
	Db.db = dbname
	dbs[dbname], _ = sql.Open("mysql", dbsmap[dbname])
	err := dbs[dbname].Ping()
	if err != nil {
		log.Fatal("M")
	}
	Db._sql_keys = make(map[string]string)
	return Db
}

type DB struct {
	db        string
	dbs       map[string]*sql.DB
	tx        *sql.Tx
	param     []string
	table     string
	join      string
	where     string
	column    string
	group     string
	having    string
	order     string
	limit     string
	_sql_keys map[string]string
}

func (db *DB) setKey(key string, val string) bool {
	if _, ok := db._sql_keys[key]; ok {
		db._sql_keys[key] = val
		return true
	}
	return false
}
func (db *DB) getKey(key string) string {
	if _, ok := db._sql_keys[key]; ok {
		return db._sql_keys[key]
	}
	return ""
}

func (db *DB) Select(columns string) *DB {
	if columns == "" {
		columns = "*"
	}
	db._sql_keys["select"] = "select " + columns
	return db
}
func (db *DB) From(table string) *DB {
	db._sql_keys["table"] = "from " + table
	return db
}
func (db *DB) Join(table string, condition string) *DB {
	if condition == "" {
		return db
	}
	if strings.Contains(condition, "=") {
		condition = "on " + condition
	} else {
		condition = "using (" + condition + ")"
	}
	db._sql_keys["joinCondition"] = condition
	if db.getKey("table") != "" {
		db._sql_keys["table"] = db.getKey("table") + " left join " + table + " " + condition
	} else {
		db._sql_keys["table"] = "from " + table
	}
	return db
}
func (db *DB) Where(where string, args []string) *DB {
	if where == "" {
		where = "1=1"
	}
	db._sql_keys["where"] = "where " + where
	db._sql_keys["args"] = strings.Join(args, ",")

	return db
}
func (db *DB) Group(group string) *DB {
	if group != "" {
		db._sql_keys["group"] = "group by " + group
	}
	return db
}
func (db *DB) Having(having string) *DB {
	if having != "" {
		db._sql_keys["having"] = "having " + having
	}
	return db
}
func (db *DB) Order(order string) *DB {
	if order != "" {
		db._sql_keys["order"] = "order by " + order
	}
	return db
}
func (db *DB) Limit(start int, offset int) *DB {
	db._sql_keys["limit"] = "limit " + strconv.Itoa(start) + "," + strconv.Itoa(offset)
	return db
}
func (db *DB) Insert(maps map[string]string) *DB {
	return db
}
func (db *DB) Update(maps map[string]string) *DB {
	return db
}
func (db *DB) Delete() *DB {
	return db
}
func (db *DB) GetAll() interface{} {
	fmt.Println(db.makeSql())
	return db.Query(db.makeSql())
	/*result := make(map[int]map[string]string)
	result[0] = map[string]string{"one": "one1", "two": "two2"}
	result[1] = map[string]string{"one": "one1", "two": "two2"}
	return result*/
}
func (db *DB) GetRow(sql string) map[string]string {

	result := make(map[int]map[string]string)
	result[0] = map[string]string{"one": "one1", "two": "two2"}
	result[1] = map[string]string{"one": "one1", "two": "two2"}
	return result[0]
}
func (db *DB) GetOne(sql string) map[string]string {

	result := make(map[int]map[string]string)
	result[0] = map[string]string{"one": "one1", "two": "two2"}
	result[1] = map[string]string{"one": "one1", "two": "two2"}
	return result[0]
}
func (db *DB) makeSql() string {
	sql := fmt.Sprintf("%v %v %v %v %v %v %v", db.getKey("select"), db.getKey("table"), db.getKey("where"), db.getKey("group"), db.getKey("having"), db.getKey("order"), db.getKey("limit"))
	return sql
}
func (db *DB) Query1(sql string) map[int]map[string]string {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()
	fmt.Println(dbs)
	rows, err := dbs[db.db].Query(db.makeSql(), db.getKey("args"))
	if err != nil {
		log.Fatal("3")
	}
	defer rows.Close()
	columns, err := rows.Columns()
	if err != nil {
		log.Fatal("4")
	}
	fmt.Println(reflect.TypeOf("e"))
	fmt.Println(dbs)
	/*fmt.Println(reflect.TypeOf(sql.RawBytes{}))
	values := make([]sql.RawBytes{}, len(columns))*/
	values := make([]string, len(columns))
	scanargs := make([]interface{}, len(columns))
	for i := range values {
		scanargs[i] = &values[i]
	}
	fmt.Println(values)
	fmt.Println(scanargs)
	n := 1
	var result = make(map[int]map[string]string)
	for rows.Next() {
		result[n] = make(map[string]string)
		err := rows.Scan(scanargs...)
		if err != nil {
			fmt.Println(err)
		}
		for i, v := range values {
			result[n][columns[i]] = string(v)
		}
		n++
	}
	fmt.Println(len(result))

	result[0] = map[string]string{"one": "one1", "two": "two2"}
	result[1] = map[string]string{"one": "one1", "two": "two2"}
	return result
}
func (db *DB) Query(sql string) interface{} {
	/*if m.db == nil {
		return errors.New("mysql not connect")
	}*/
	var query = strings.TrimSpace(sql)
	s, err := regexp.MatchString(`(?i)^select`, query)

	if err == nil && s == true {
		fmt.Println(reflect.TypeOf(dbs[db.db]))
		result, err := dbs[db.db].Query(sql, db.getKey("args"))
		fmt.Println(err)
		fmt.Println(result)
		c := QueryResult(result)
		fmt.Println(db.db)
		return c
	}
	exec, err := regexp.MatchString(`(?i)^(update|delete)`, query)
	if err == nil && exec == true {
		m_exec, err := dbs[db.db].Exec(query)
		if err != nil {
			return err
		}
		num, _ := m_exec.RowsAffected()
		id := strconv.FormatInt(num, 10)
		return id
	}

	insert, err := regexp.MatchString(`(?i)^insert`, query)
	if err == nil && insert == true {
		m_exec, err := dbs[db.db].Exec(query)
		if err != nil {
			return err
		}
		num, _ := m_exec.LastInsertId()
		id := strconv.FormatInt(num, 10)
		return id
	}
	result, _ := dbs[db.db].Exec(query)

	return result

}

func QueryResult(rows *sql.Rows) map[int]map[string]string {
	var result = make(map[int]map[string]string)
	columns, _ := rows.Columns()
	values := make([]sql.RawBytes, len(columns))
	scanargs := make([]interface{}, len(values))
	for i := range values {
		scanargs[i] = &values[i]
	}

	var n = 1
	for rows.Next() {
		result[n] = make(map[string]string)
		err := rows.Scan(scanargs...)

		if err != nil {
			fmt.Println(err)
		}

		for i, v := range values {
			result[n][columns[i]] = string(v)
		}
		n++
	}

	return result
}

/*func (db *DB) Query(sql string) interface{} {
	if dbs[db.db] == nil {
		return errors.New("mysql not connect")
	}
	var query = strings.TrimSpace(sql)
	s, err := regexp.MatchString(`(?i)^select`, query)
	if err == nil && s == true {
		result, _ := dbs[db.db].Query(db.makeSql())
		c := QueryResult(result)
		return c
	}
	exec, err := regexp.MatchString(`(?i)^(update|delete)`, query)
	if err == nil && exec == true {
		m_exec, err := m.db.Exec(query)
		if err != nil {
			return err
		}
		num, _ := m_exec.RowsAffected()
		id := strconv.FormatInt(num, 10)
		return id
	}

	insert, err := regexp.MatchString(`(?i)^insert`, query)
	if err == nil && insert == true {
		m_exec, err := m.db.Exec(query)
		if err != nil {
			return err
		}
		num, _ := m_exec.LastInsertId()
		id := strconv.FormatInt(num, 10)
		return id
	}
	result, _ := m.db.Exec(query)

	return result

}*/
func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()
	where := []string{"3"}
	tt := M("db0").Select("*").From("article").Where("id>?", where).Group("id").Order("id").Limit(0, 1).GetAll()
	fmt.Println(tt)
	fmt.Println("--------------")
	db, err := sql.Open("mysql", "slave:slave@tcp(weidiane.54json.com:3306)/blog?charset=utf8")
	//defer db.Close()

	if err != nil {
		log.Fatal("1")
	}
	err = db.Ping()
	if err != nil {
		log.Fatal("2")
	}
	rows, err := db.Query("select title,ctime from article where id>?", 1)

	if err != nil {
		log.Fatal("3")
	}
	defer rows.Close()
	columns, err := rows.Columns()
	if err != nil {
		log.Fatal("4")
	}
	values := make([]sql.RawBytes, len(columns))
	scanargs := make([]interface{}, len(columns))
	for i := range values {
		scanargs[i] = &values[i]
	}
	fmt.Println(values)
	fmt.Println(scanargs)
	n := 1
	var result = make(map[int]map[string]string)
	for rows.Next() {
		result[n] = make(map[string]string)
		err := rows.Scan(scanargs...)
		if err != nil {
			fmt.Println(err)
		}
		for i, v := range values {
			result[n][columns[i]] = string(v)
		}
		n++
	}
	fmt.Println(len(result))
	/*for p, q := range result {
		fmt.Println(p)
		fmt.Println(q)
	}*/
	//fmt.Println(result)
}
